<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="ROS杂篇 ROS中使用Kinect V2 Part2：iai-kinect使用, python,machine learning,deep learning,html,css,c,c++,cpp,cmake,ros,linux,ubuntu">
    <meta name="description" content="本篇详细介绍了iai-kinect2功能包，在此基础上通过iai-kinect2获取深度图像，从而进行ROS中的开发。">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="referrer" content="no-referrer-when-downgrade">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>ROS杂篇 ROS中使用Kinect V2 Part2：iai-kinect使用 | JackWang&#39;s Blog</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/all.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery-3.6.0.min.js"></script>

<meta name="generator" content="Hexo 5.4.2">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css">
<link rel="stylesheet" href="/css/prism-line-numbers.css" type="text/css"></head>



   <style>
    body{
       background-image: url(https://cdn.jsdelivr.net/gh/Tokisaki-Galaxy/res/site/medias/background.jpg);
       background-repeat:no-repeat;
       background-size: 100% 100%;
       background-attachment:fixed;
    }
</style>



<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/" class="waves-effect waves-light">
                    
                    <img src="/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">JackWang&#39;s Blog</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="" class="waves-effect waves-light">

      
      <i class="fas fa-book-reader" style="zoom: 0.6;"></i>
      
      <span>博客</span>
      <i class="fas fa-chevron-down" aria-hidden="true" style="zoom: 0.6;"></i>
    </a>
    <ul class="sub-nav menus_item_child ">
      
      <li>
        <a href="/tags">
          
          <i class="fas fa-tags" style="margin-top: -20px; zoom: 0.6;"></i>
          
	  <span>按标签归类文章</span>
        </a>
      </li>
      
      <li>
        <a href="/categories">
          
          <i class="fas fa-bookmark" style="margin-top: -20px; zoom: 0.6;"></i>
          
	  <span>按目录归类文章</span>
        </a>
      </li>
      
      <li>
        <a href="/archives">
          
          <i class="fas fa-archive" style="margin-top: -20px; zoom: 0.6;"></i>
          
	  <span>按日期分类文章</span>
        </a>
      </li>
      
    </ul>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>



<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">JackWang&#39;s Blog</div>
        <div class="logo-desc">
            
            JackWang的个人博客
            
        </div>
    </div>

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="javascript:;">
			
				<i class="fa-fw fas fa-book-reader"></i>
			
			博客
			<span class="m-icon"><i class="fas fa-chevron-right"></i></span>
		</a>
            <ul  style="background:  ;" >
              
                <li>

                  <a href="/tags " style="margin-left:75px">
				  
				   <i class="fa fas fa-tags" style="position: absolute;left:50px" ></i>
			      
                              <span>按标签归类文章</    span>

                  </a>
                </li>
              
                <li>

                  <a href="/categories " style="margin-left:75px">
				  
				   <i class="fa fas fa-bookmark" style="position: absolute;left:50px" ></i>
			      
                              <span>按目录归类文章</    span>

                  </a>
                </li>
              
                <li>

                  <a href="/archives " style="margin-left:75px">
				  
				   <i class="fa fas fa-archive" style="position: absolute;left:50px" ></i>
			      
                              <span>按日期分类文章</    span>

                  </a>
                </li>
              
            </ul>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        
    </ul>
</div>


        </div>

        
    </nav>

</header>

    
<script src="/libs/cryptojs/crypto-js.min.js"></script>
<script>
    (function() {
        let pwd = '';
        if (pwd && pwd.length > 0) {
            if (pwd !== CryptoJS.SHA256(prompt('抱歉，这篇文章并不想让所有人都看到，请输入授权密码观看')).toString(CryptoJS.enc.Hex)) {
                alert('密码错误，将返回主页！');
                location.href = '/';
            }
        }
    })();
</script>




<div class="bg-cover pd-header post-cover" style="background-image: url('https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211121155602208.png')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">ROS杂篇 ROS中使用Kinect V2 Part2：iai-kinect使用</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/tags/Ubuntu/">
                                <span class="chip bg-color">Ubuntu</span>
                            </a>
                        
                            <a href="/tags/ROS/">
                                <span class="chip bg-color">ROS</span>
                            </a>
                        
                            <a href="/tags/roslaunch/">
                                <span class="chip bg-color">roslaunch</span>
                            </a>
                        
                            <a href="/tags/cv-bridge/">
                                <span class="chip bg-color">cv_bridge</span>
                            </a>
                        
                            <a href="/tags/melodic/">
                                <span class="chip bg-color">melodic</span>
                            </a>
                        
                            <a href="/tags/OpenCv/">
                                <span class="chip bg-color">OpenCv</span>
                            </a>
                        
                            <a href="/tags/sensor-msgs/">
                                <span class="chip bg-color">sensor_msgs</span>
                            </a>
                        
                            <a href="/tags/Kinect-V2/">
                                <span class="chip bg-color">Kinect V2</span>
                            </a>
                        
                            <a href="/tags/iai-kinect2/">
                                <span class="chip bg-color">iai-kinect2</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/categories/ROS%E6%9D%82%E7%AF%87/" class="post-category">
                                ROS杂篇
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-11-19
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>更新日期:&nbsp;&nbsp;
                    2023-06-01
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    7.1k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    32 分
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>阅读次数:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">

        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <blockquote>
<p>本篇详细介绍了iai-kinect2功能包，在此基础上通过iai-kinect2获取深度图像，从而进行ROS中的开发。</p>
</blockquote>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211121155602208.png" alt="使用Kinect V2获取得到图像经过YOLO检测并与深度配准"></p>
<span id="more"></span>
<h1 id="ROS杂篇-ROS中使用Kinect-V2-Part2：iai-kinect2使用"><a href="#ROS杂篇-ROS中使用Kinect-V2-Part2：iai-kinect2使用" class="headerlink" title="ROS杂篇 ROS中使用Kinect V2 Part2：iai-kinect2使用"></a>ROS杂篇 ROS中使用Kinect V2 Part2：iai-kinect2使用</h1><blockquote>
<p>前言：为什么要写这篇博客</p>
</blockquote>
<p>在上一篇中，我们介绍了如何在<code>Ubuntu</code>上安装<code>Kinect V2</code>的开原驱动：<code>libfrenect2</code>，以及如何安装在<code>ROS</code>中使用<code>libfrenect2</code>获取深度图像的功能包<code>iai-kinect2</code>。然而在上一篇文章的最后，我们只是简单的使用了一下<code>iai-kinect2</code>功能包。但是我们通过<code>rostopic list</code>却看到了非常多的话题，那么这些话题之间到底是什么关系呢？又该如何基于<code>iai-kinect2</code>进行深度开发呢？</p>
<p>本节就将在上一篇的基础上，在介绍<code>iai-kinect2</code>的基础上，利用<code>iai-kinect2</code>进行开发。如果没有看过第一篇文章、没有配置好环境，先按照<a target="_blank" rel="noopener" href="http://jackwang.cafe/2021/11/18/ros-za-pian-an-zhuang-kinect-v2-qu-dong/">第一篇文章中的教程</a>跟着来。</p>
<p>废话不多说，下面就开始吧。</p>
<h2 id="1-什么是iai-kinect2？"><a href="#1-什么是iai-kinect2？" class="headerlink" title="1. 什么是iai-kinect2？"></a>1. 什么是iai-kinect2？</h2><blockquote>
<p>我认为合理的学习方法：学什么前，先问是什么，再问为什么学（学习这个东西的目的），搞懂学了能为我们带来那些帮助，最后再开始学</p>
</blockquote>
<p>如果你有看过我的上一篇博客的话，你应该就会知道，<code>iai-kinect2</code>是<code>ROS</code>的一个功能包，他的作用在于调用了<code>libfreenect2</code>驱动来获得<code>Kinect V2</code>相机得到的深度图像以及通过<code>OpenGL</code>、<code>CUDA</code>、<code>CPU</code>等平台极大地提升了渲染速度和适应性。最终实现了多平台下深度图像30 FPS的性能。</p>
<p>下面是对<code>iai-kinect2</code>的更加详细的介绍</p>
<h3 id="A-谁开发的iai-kinect2"><a href="#A-谁开发的iai-kinect2" class="headerlink" title="A. 谁开发的iai-kinect2?"></a>A. 谁开发的iai-kinect2?</h3><p>iai-kinect2是由德国不莱梅大学（University of Bremen）的博士生Thiemo Wiedemeyer。他在2013年的时候去不莱梅大学的人工智能研究所读博的时候开发出了<code>iai-kinect2</code>。在2014年的时候，经过几个月的开发，他和他组里的另外一个负责串口相关部分的博士生合作，最终完成了这个非常好用的库，并在ROS的论坛上发布了这一消息。</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120010505103.png" alt="Thiemo Wiedemeyer在ROS论坛上发布这个功能包的帖子"></p>
<h3 id="B-iai-kinect2的组成"><a href="#B-iai-kinect2的组成" class="headerlink" title="B. iai-kinect2的组成"></a>B. iai-kinect2的组成</h3><p>前面我们只是从大体上直到了<code>iai-kinect2</code>是一个<code>ROS</code>的功能包，他调用了<code>libfreenect2</code>来获取深度图像。其实更准确的说，<code>iai-kinect2</code>是<code>ROS</code>的一个<strong>元功能包</strong>。</p>
<blockquote>
<p><strong>什么是元功能包？</strong></p>
<p><code>ROS</code>中有一些基础的概念：工作空间、源码空间、编译空间、开发空间、功能包、元功能包、发行版等等。</p>
<p>通常我们工作是在一个工作空间中，这个工作空间中包含了我们开发的一切：我们的源代码、生成的库文件、生成的头文件、得到的可执行文件……而我们写的代码都以功能包的形式组织起来，我们在发布代码的时候就是以功能包的形式进行发布。而通常几个具有相关功能的功能包组合在一起就是一个元功能包，我们通过元功能包将几个功能包组合起来，使得他们成为一个整体来进行发布。</p>
<p>在下图中，我们所有的代码都在catkin_workspace这个工作空间中（挖个坑，以后写写文章讲讲什么是<code>catkin</code>）。而具体来说，我们的源代码存放在<code>src</code>源码空间中，我们通过<code>catkin_make</code>会对我们所有的源代码进行编译，编译过程中产生的中间文件，例如<code>Cmake</code>的<code>module</code>以及<code>Makefile</code>等等都在<code>build</code>编译空间中。我们最后的可执行文件和我们自己写的库文件都在<code>devel</code>开发空间中。对于源码空间中，一个package就负责实现一个具体的功能，例如读取摄像头、抓取物体等等。如果package1和package2有所关联，例如package1是读取摄像头的功能包，而package2是驱动机械臂的功能包，那么他们两个在一起可以完成机器人抓取物体这个功能，那么这个时候，我们就可以新建一个功能包，这个功能包什么都没有，只有表明这两个功能包在一起组成一个元功能包的配置信息，即描述元功能包架构的功能包。在下面就是iai-kinect2这个功能包</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/文件系统.jpg" alt="ROS中的基础概念/文件系统"></p>
</blockquote>
<p>具体来说，<code>iai-kinect2</code>这个元功能包由几个功能包组成：<code>iai-kinect2</code>（元功能包描述功能包）、<code>kinect2_bridge</code>（负责调用libfreenect2、OpenGL获取图像的功能包）、<code>kinect_calibration</code>（提供了Kinect V2相机GUI校准的功能包）、<code>kinect_registration</code>（负责点云和深度图像配准的功能包）以及<code>kinect_viewer</code>（提供了简单的可视化功能的功能包）。</p>
<p>具体功能包的架构可以看下图</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120012913705.png" alt="iai-kinect2元功能包的架构"></p>
<h3 id="C-iai-kinect2的功能"><a href="#C-iai-kinect2的功能" class="headerlink" title="C. iai-kinect2的功能"></a>C. iai-kinect2的功能</h3><p>关于<code>iai-kinect2</code>的功能，我们前面其实已经体验过了他的可视化和获取深度图像以及点云和彩色图像的配准。因此这里主要关注<code>iai-kinect2</code>中的标定功能。</p>
<blockquote>
<p>众所周知，我们利用相机除了拍照以外，还有一个重要的功能就是从相机获取的图像信息出发计算三维空间中物体的几何信息并由此重建和识别物体。这也是计算机视觉的基本任务之一。那么我们在进行推断的时候就存在一些问题，其中最主要的一个问题就是相机的镜头畸变，即由于相机的镜头是一个凹透镜导致物体间真实的距离被扭曲。因此我们需要通过一些手段来进行修正。进行修正之后会得到一些参数，利用这些参数我们就可以对畸变的图像进行修正，以实现获得物体间精准的位置。由于这个参数和相机的镜头、角度有关，因此他们又叫做相机参数。通过标定我们就能够获得这些参数。</p>
<p>例如在下图中，我们可以直到机器人和地板的线都应该是直线，但是由于畸变导致原本直的线歪曲，这个现象在图像边缘处尤为明显。</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120021326327.png" alt="相机畸变修正的例子"></p>
<p>当然除了畸变以外还有世界坐标转相机坐标等等问题，他们统称为相机参数。</p>
<p>关于相机标定的更多内容，推荐参考搜狐上的博客：<a target="_blank" rel="noopener" href="https://www.sohu.com/a/336803765_120071391">https://www.sohu.com/a/336803765_120071391</a></p>
</blockquote>
<p><code>iai-kinect2</code>中直接提供了用于相机标定的程序，因此我们可以直接在命令行中进行调用即可。关于如何进行校准，参考<a target="_blank" rel="noopener" href="https://github.com/code-iai/iai_kinect2/tree/master/kinect2_calibration#calibrating-the-kinect-one">github上的readme</a></p>
<p>最终通过标定，可以实现的效果如下。可以看出来，原本倾斜的图像被校准了。</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/68747470733a2f2f61692e756e692d6272656d656e2e64652f5f6d656469612f6b696e656374325f636c6f75645f6e6f63616c69622e706e67" alt="未校准前的点云图像"></p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/68747470733a2f2f61692e756e692d6272656d656e2e64652f5f6d656469612f6b696e656374325f636c6f75645f63616c69622e706e67" alt="校准后的点云图像"></p>
<h2 id="2-iai-kinect2的使用"><a href="#2-iai-kinect2的使用" class="headerlink" title="2. iai-kinect2的使用"></a>2. iai-kinect2的使用</h2><p>我们在下面将对<code>iai-kinect2</code>的使用进行介绍，不过需要说明的是：由于<code>iai-kinect2</code>的代码非常好，将自己尽可能的低耦合，因此其所有的依赖都是<code>ROS</code>的标准消息。因此，我们学习iai-kinect2的使用主要是从下面两个方面去学习</p>
<ul>
<li><code>iai-kinect2</code>中使用的<code>ROS</code>的标准消息：<code>Image</code>和<code>CompressedImage</code></li>
<li><code>iai-kinect2</code>中每个话题的含义和作用</li>
</ul>
<h3 id="A-ROS中Image和CompressedImage"><a href="#A-ROS中Image和CompressedImage" class="headerlink" title="A. ROS中Image和CompressedImage"></a>A. ROS中Image和CompressedImage</h3><p><code>ROS</code>中为图像数据提供了两个官方的消息类型：<code>Image</code>和<code>CompressedImage</code>。其中<code>Image</code>是没有经过压缩的图片而<code>CompressedImage</code>则是经过压缩的图片。由与<code>ROS</code>中的所有的消息其实都是基于<code>std_msgs</code>提供的基础数据类型上定义的，因此<code>Image</code>和<code>CompressedImage</code>也不例外。具体来说，图片本身是用一个装着字节流的数组保存的，而图片的<code>frame_id</code>和对应的相机信息等等都是有对应的项。</p>
<h4 id="消息定义"><a href="#消息定义" class="headerlink" title="消息定义"></a>消息定义</h4><p>首先是<code>Image</code>消息的定义，可以看到<code>header</code>中提供时间戳等信息，而图像的长宽、字节序、编码方式等等内容都是用于帮助解码<code>data</code>字节流的。此外也能够看到，<code>ROS</code>中的图像每一个像素都是用一个8位无符号整数描述的。</p>
<pre class="line-numbers language-msg"><code class="language-msg"># This message contains an uncompressed image
# (0, 0) is at top-left corner of image
#

Header header        # Header timestamp should be acquisition time of image
                     # Header frame_id should be optical frame of camera
                     # origin of frame should be optical center of camera
                     # +x should point to the right in the image
                     # +y should point down in the image
                     # +z should point into to plane of the image
                     # If the frame_id here and the frame_id of the CameraInfo
                     # message associated with the image conflict
                     # the behavior is undefined

uint32 height         # image height, that is, number of rows
uint32 width          # image width, that is, number of columns

# The legal values for encoding are in file src/image_encodings.cpp
# If you want to standardize a new string format, join
# ros-users@lists.sourceforge.net and send an email proposing a new encoding.

string encoding       # Encoding of pixels -- channel meaning, ordering, size
                      # taken from the list of strings in include/sensor_msgs/image_encodings.h

uint8 is_bigendian    # is this data bigendian?
uint32 step           # Full row length in bytes
uint8[] data          # actual matrix data, size is (step * rows)
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>类似的，<code>CompressedImage</code>则是经过压缩的图像，具体的压缩方式就是使用<code>jpg</code>、<code>png</code>等编码格式，因此图像的编码方式是固定的</p>
<pre class="line-numbers language-tmsg"><code class="language-tmsg">Header header        # Header timestamp should be acquisition time of image
                     # Header frame_id should be optical frame of camera
                     # origin of frame should be optical center of camera
                     # +x should point to the right in the image
                     # +y should point down in the image
                     # +z should point into to plane of the image

string format        # Specifies the format of the data
                     #   Acceptable values:
                     #     jpeg, png
uint8[] data         # Compressed image buffer
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>最后需要注意的是<code>iai-kinect2</code>中还用到了<code>camerainfo</code>这个<code>ROS</code>的官方消息，其内容如下，主要定义了相机的内外参数，获取图像的分辨率等信息</p>
<pre class="line-numbers language-msg"><code class="language-msg"># This message defines meta information for a camera. It should be in a
# camera namespace on topic "camera_info" and accompanied by up to five
# image topics named:
#
#   image_raw - raw data from the camera driver, possibly Bayer encoded
#   image            - monochrome, distorted
#   image_color      - color, distorted
#   image_rect       - monochrome, rectified
#   image_rect_color - color, rectified
#
# The image_pipeline contains packages (image_proc, stereo_image_proc)
# for producing the four processed image topics from image_raw and
# camera_info. The meaning of the camera parameters are described in
# detail at http://www.ros.org/wiki/image_pipeline/CameraInfo.
#
# The image_geometry package provides a user-friendly interface to
# common operations using this meta information. If you want to, e.g.,
# project a 3d point into image coordinates, we strongly recommend
# using image_geometry.
#
# If the camera is uncalibrated, the matrices D, K, R, P should be left
# zeroed out. In particular, clients may assume that K[0] == 0.0
# indicates an uncalibrated camera.

#######################################################################
#                     Image acquisition info                          #
#######################################################################

# Time of image acquisition, camera coordinate frame ID
Header header    # Header timestamp should be acquisition time of image
                 # Header frame_id should be optical frame of camera
                 # origin of frame should be optical center of camera
                 # +x should point to the right in the image
                 # +y should point down in the image
                 # +z should point into the plane of the image


#######################################################################
#                      Calibration Parameters                         #
#######################################################################
# These are fixed during camera calibration. Their values will be the #
# same in all messages until the camera is recalibrated. Note that    #
# self-calibrating systems may "recalibrate" frequently.              #
#                                                                     #
# The internal parameters can be used to warp a raw (distorted) image #
# to:                                                                 #
#   1. An undistorted image (requires D and K)                        #
#   2. A rectified image (requires D, K, R)                           #
# The projection matrix P projects 3D points into the rectified image.#
#######################################################################

# The image dimensions with which the camera was calibrated. Normally
# this will be the full camera resolution in pixels.
uint32 height
uint32 width

# The distortion model used. Supported models are listed in
# sensor_msgs/distortion_models.h. For most cameras, "plumb_bob" - a
# simple model of radial and tangential distortion - is sufficient.
string distortion_model

# The distortion parameters, size depending on the distortion model.
# For "plumb_bob", the 5 parameters are: (k1, k2, t1, t2, k3).
float64[] D

# Intrinsic camera matrix for the raw (distorted) images.
#     [fx  0 cx]
# K = [ 0 fy cy]
#     [ 0  0  1]
# Projects 3D points in the camera coordinate frame to 2D pixel
# coordinates using the focal lengths (fx, fy) and principal point
# (cx, cy).
float64[9]  K # 3x3 row-major matrix

# Rectification matrix (stereo cameras only)
# A rotation matrix aligning the camera coordinate system to the ideal
# stereo image plane so that epipolar lines in both stereo images are
# parallel.
float64[9]  R # 3x3 row-major matrix

# Projection/camera matrix
#     [fx'  0  cx' Tx]
# P = [ 0  fy' cy' Ty]
#     [ 0   0   1   0]
# By convention, this matrix specifies the intrinsic (camera) matrix
#  of the processed (rectified) image. That is, the left 3x3 portion
#  is the normal camera intrinsic matrix for the rectified image.
# It projects 3D points in the camera coordinate frame to 2D pixel
#  coordinates using the focal lengths (fx', fy') and principal point
#  (cx', cy') - these may differ from the values in K.
# For monocular cameras, Tx = Ty = 0. Normally, monocular cameras will
#  also have R = the identity and P[1:3,1:3] = K.
# For a stereo pair, the fourth column [Tx Ty 0]' is related to the
#  position of the optical center of the second camera in the first
#  camera's frame. We assume Tz = 0 so both cameras are in the same
#  stereo image plane. The first camera always has Tx = Ty = 0. For
#  the right (second) camera of a horizontal stereo pair, Ty = 0 and
#  Tx = -fx' * B, where B is the baseline between the cameras.
# Given a 3D point [X Y Z]', the projection (x, y) of the point onto
#  the rectified image is given by:
#  [u v w]' = P * [X Y Z 1]'
#         x = u / w
#         y = v / w
#  This holds for both images of a stereo pair.
float64[12] P # 3x4 row-major matrix


#######################################################################
#                      Operational Parameters                         #
#######################################################################
# These define the image region actually captured by the camera       #
# driver. Although they affect the geometry of the output image, they #
# may be changed freely without recalibrating the camera.             #
#######################################################################

# Binning refers here to any camera setting which combines rectangular
#  neighborhoods of pixels into larger "super-pixels." It reduces the
#  resolution of the output image to
#  (width / binning_x) x (height / binning_y).
# The default values binning_x = binning_y = 0 is considered the same
#  as binning_x = binning_y = 1 (no subsampling).
uint32 binning_x
uint32 binning_y

# Region of interest (subwindow of full camera resolution), given in
#  full resolution (unbinned) image coordinates. A particular ROI
#  always denotes the same window of pixels on the camera sensor,
#  regardless of binning settings.
# The default setting of roi (all values 0) is considered the same as
#  full resolution (roi.width = width, roi.height = height).
RegionOfInterest roi
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>关于其他传感器消息，参考<code>roswiki</code>的文章：<a target="_blank" rel="noopener" href="http://wiki.ros.org/sensor_msgs">http://wiki.ros.org/sensor_msgs</a></p>
<p>关于全部的官方消息，参考<code>roswiki</code>文章：<a target="_blank" rel="noopener" href="http://wiki.ros.org/common_msgs?distro=noetic">http://wiki.ros.org/common_msgs?distro=noetic</a></p>
<h4 id="使用cv-bridge转接给OpenCV"><a href="#使用cv-bridge转接给OpenCV" class="headerlink" title="使用cv_bridge转接给OpenCV"></a>使用cv_bridge转接给OpenCV</h4><p>需要注意的是，上面的方式的到的图像都是<code>ROS</code>中定义的图像的消息，而<code>ROS</code>中的图像的消息和<code>OpenCV</code>的并不一样，因此如果我们后续还要对图像进行处理的话，就需要将<code>ROS</code>中的图像转变为<code>OpenCV</code>的图像。为此我们就需要使用<code>CV_bridge</code>。</p>
<p>ROS中的图像和OpenCV中的图像不一样的地方在于，<code>ROS</code>是通过字节流以及辅助的解码信息来表示一张图像，而OpenCV则是通过其核心的<code>lplImage</code>数据结构来表示一张图像（<code>lpl</code>表示 <code>Intel Image Processing Library</code>）。<code>lplImage</code>的定义如下，当然我们没必要全部搞懂，看看定义知道不同即可。</p>
<p>此外<code>Python</code>中<code>OpenCV</code>的图像的表示是基于<code>Num Py</code>的，因此还会存在不一样的地方。</p>
<pre class="line-numbers language-c++"><code class="language-c++">typedef struct _IplImage  
    {  
        int  nSize;         /* IplImage大小 */  
        int  ID;            /* 版本 (=0)*/  
        int  nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */  
        int  alphaChannel;  /* 被OpenCV忽略 */  
        int  depth;         /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U, 
                               IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */  
        char colorModel[4]; /* 被OpenCV忽略 */  
        char channelSeq[4]; /* 同上 */  
        int  dataOrder;     /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道. 
                               cvCreateImage只能创建交叉存取图像 */  
        int  origin;        /* 0 - 顶—左结构, 
                               1 - 底—左结构 (Windows bitmaps 风格) */  
        int  align;         /* 图像行排列 (4 or 8). OpenCV 忽略它，使用 widthStep 代替 */  
        int  width;         /* 图像宽像素数 */  
        int  height;        /* 图像高像素数*/  
        struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */  
        struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */  
        void  *imageId;     /* 同上*/  
        struct _IplTileInfo *tileInfo; /*同上*/  
        int  imageSize;     /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep），单位字节*/  
        char *imageData;  /* 指向排列的图像数据 */  
        int  widthStep;   /* 排列的图像行大小，以字节为单位 */  
        int  BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */  
        int  BorderConst[4]; /* 同上 */  
        char *imageDataOrigin; /* 指针指向一个不同的图像数据结构（不是必须排列的），是为了纠正图像内存分配准备的 */  
    }  
    IplImage;
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>所以<code>cv_bridge</code>的功能就是下面这张图中所表述的</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/cv_bridge" alt="cv_bridge的作用"></p>
<p>更多关于<code>cv_bridge</code>的问题，参考<code>roswiki</code>：<a target="_blank" rel="noopener" href="https://wiki.ros.org/cv_bridge">https://wiki.ros.org/cv_bridge</a></p>
<p>此外，需要注意的是，在<code>Melodic</code>下在<code>Python</code>中使用cv_bridge会报错无法加载一个so/dynamic啥啥啥，关于这个问题的解决，先挖个坑，以后再补。</p>
<h3 id="B-iai-kinect2中每个话题的含义和作用"><a href="#B-iai-kinect2中每个话题的含义和作用" class="headerlink" title="B. iai-kinect2中每个话题的含义和作用"></a>B. iai-kinect2中每个话题的含义和作用</h3><p>当我们以<code>launch</code>文件的形式运行<code>iai-kinect2</code>后，我们会看到很多的话题，这些话题其实分成三组：<code>hd</code>、<code>qhd</code>和<code>sd</code>。需要注意的是，每组话题下的<code>points</code>话题都只是只有通过<code>launch</code>文件运行才会看到的。</p>
<h4 id="HD话题"><a href="#HD话题" class="headerlink" title="HD话题"></a>HD话题</h4><p>HD话题其实指的是高分辨率的图像，由于<code>Kinect V2</code>相比<code>Kinect V1</code>，其图像极限分辨率1920x1080，因此HD话题中所有的图像都是极限分辨率1920x1080的图像</p>
<p>此外，HD话题下发布的color表示是RGB彩色图像、<code>color_rect</code>则是经过畸变处理（rectified）的图像，<code>compressed</code>的则是经过压缩的图像。depth则是深度图，<code>mono</code>则是单色灰度图。</p>
<pre class="line-numbers language-text"><code class="language-text">/kinect2/hd/camera_info
/kinect2/hd/image_color
/kinect2/hd/image_color/compressed
/kinect2/hd/image_color_rect
/kinect2/hd/image_color_rect/compressed
/kinect2/hd/image_depth_rect
/kinect2/hd/image_depth_rect/compressed
/kinect2/hd/image_mono
/kinect2/hd/image_mono/compressed
/kinect2/hd/image_mono_rect
/kinect2/hd/image_mono_rect/compressed
/kinect2/hd/points
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="QHD话题"><a href="#QHD话题" class="headerlink" title="QHD话题"></a>QHD话题</h4><p>QHD话题的全称是Quater HD，即该话题是HD话题的1/4。原因在于HD话题下的图片实在是太大了，因此无论是数据的传输还是处理都很慢。所以QHD中的图像是对HD的图像进行降采样之后的图像，长宽各自降采样一半，所以是512x424的图片。因此图像处理起来速度很快</p>
<pre class="line-numbers language-text"><code class="language-text">/kinect2/qhd/camera_info
/kinect2/qhd/image_color
/kinect2/qhd/image_color/compressed
/kinect2/qhd/image_color_rect
/kinect2/qhd/image_color_rect/compressed
/kinect2/qhd/image_depth_rect
/kinect2/qhd/image_depth_rect/compressed
/kinect2/qhd/image_mono
/kinect2/qhd/image_mono/compressed
/kinect2/qhd/image_mono_rect
/kinect2/qhd/image_mono_rect/compressed
/kinect2/qhd/points
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="SD话题"><a href="#SD话题" class="headerlink" title="SD话题"></a>SD话题</h4><p>SD话题中的图像都是从相机获得的红外和深度图像，因此大小都是原本的大小：512x424，处理起来速度还是比较快的。</p>
<pre class="line-numbers language-text"><code class="language-text">/kinect2/sd/camera_info
/kinect2/sd/image_color_rect
/kinect2/sd/image_color_rect/compressed
/kinect2/sd/image_depth
/kinect2/sd/image_depth/compressed
/kinect2/sd/image_depth_rect
/kinect2/sd/image_depth_rect/compressed
/kinect2/sd/image_ir
/kinect2/sd/image_ir/compressed
/kinect2/sd/image_ir_rect
/kinect2/sd/image_ir_rect/compressed
/kinect2/sd/points
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="C-launch启动节点时候指定参数"><a href="#C-launch启动节点时候指定参数" class="headerlink" title="C. launch启动节点时候指定参数"></a>C. launch启动节点时候指定参数</h3><p>由于iai-kinect2自成一套系统，因此我们没有必要也很难修改他的代码来完成我们需要的功能。为此<code>iai-kinect2</code>的<code>launch</code>文件支持在启动的时候指定参数，来实现不同的功能，具体所有的参数如下</p>
<pre class="line-numbers language-bash"><code class="language-bash">roslaunch kinect2_bridge kinect2_bridge.launch <span class="token punctuation">[</span>options:<span class="token operator">=</span>value<span class="token punctuation">]</span>
base_name:<span class="token operator">=</span><span class="token operator">&lt;</span>string<span class="token operator">></span>
    default: kinect2
    info:    <span class="token keyword">set</span> base name <span class="token keyword">for</span> all topics
sensor:<span class="token operator">=</span><span class="token operator">&lt;</span>string<span class="token operator">></span>
    default:
    info:    serial of the sensor to use
fps_limit:<span class="token operator">=</span><span class="token operator">&lt;</span>double<span class="token operator">></span>
    default: -1.0
    info:    limit the frames per second
calib_path:<span class="token operator">=</span><span class="token operator">&lt;</span>string<span class="token operator">></span>
    default: /home/wiedemeyer/work/src/iai_kinect2/kinect2_bridge/data/
    info:    path to the calibration files
use_png:<span class="token operator">=</span><span class="token operator">&lt;</span>bool<span class="token operator">></span>
    default: <span class="token boolean">false</span>
    info:    Use PNG compression instead of TIFF
jpeg_quality:<span class="token operator">=</span><span class="token operator">&lt;</span>int<span class="token operator">></span>
    default: 90
    info:    JPEG quality level from 0 to 100
png_level:<span class="token operator">=</span><span class="token operator">&lt;</span>int<span class="token operator">></span>
    default: 1
    info:    PNG compression level from 0 to 9
depth_method:<span class="token operator">=</span><span class="token operator">&lt;</span>string<span class="token operator">></span>
    default: cuda
    info:    Use specific depth processing: default, cpu, opengl, opencl, cuda, clkde, cudakde
depth_device:<span class="token operator">=</span><span class="token operator">&lt;</span>int<span class="token operator">></span>
    default: -1
    info:    openCL device to use <span class="token keyword">for</span> depth processing
reg_method:<span class="token operator">=</span><span class="token operator">&lt;</span>string<span class="token operator">></span>
    default: opencl
    info:    Use specific depth registration: default, cpu, opencl
reg_device:<span class="token operator">=</span><span class="token operator">&lt;</span>int<span class="token operator">></span>
    default: -1
    info:    openCL device to use <span class="token keyword">for</span> depth registration
max_depth:<span class="token operator">=</span><span class="token operator">&lt;</span>double<span class="token operator">></span>
    default: 12.0
    info:    max depth value
min_depth:<span class="token operator">=</span><span class="token operator">&lt;</span>double<span class="token operator">></span>
    default: 0.1
    info:    min depth value
queue_size:<span class="token operator">=</span><span class="token operator">&lt;</span>int<span class="token operator">></span>
    default: 2
    info:    queue size of publisher
bilateral_filter:<span class="token operator">=</span><span class="token operator">&lt;</span>bool<span class="token operator">></span>
    default: <span class="token boolean">true</span>
    info:    <span class="token function">enable</span> bilateral filtering of depth images
edge_aware_filter:<span class="token operator">=</span><span class="token operator">&lt;</span>bool<span class="token operator">></span>
    default: <span class="token boolean">true</span>
    info:    <span class="token function">enable</span> edge aware filtering of depth images
publish_tf:<span class="token operator">=</span><span class="token operator">&lt;</span>bool<span class="token operator">></span>
    default: <span class="token boolean">false</span>
    info:    publish static tf transforms <span class="token keyword">for</span> camera
base_name_tf:<span class="token operator">=</span><span class="token operator">&lt;</span>string<span class="token operator">></span>
    default: as base_name
    info:    base name <span class="token keyword">for</span> the tf frames
worker_threads:<span class="token operator">=</span><span class="token operator">&lt;</span>int<span class="token operator">></span>
    default: 4
    info:    number of threads used <span class="token keyword">for</span> processing the images
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="3-iai-kinect2使用示例"><a href="#3-iai-kinect2使用示例" class="headerlink" title="3. iai-kinect2使用示例"></a>3. iai-kinect2使用示例</h2><p>经过上面的介绍，我们对于如何使用iai-kinect2来获得深度图像和点云应该有了认识，下面我们就给出几个使用的例子。</p>
<p>其实使用的具体流程很简单，就是去订阅HD、QHD、SD话题中的消息，然后使用CV_Bridge转换成OpenCV的图像，然后再使用OpenCV进行视频图像的处理。</p>
<h3 id="A-图像显示"><a href="#A-图像显示" class="headerlink" title="A. 图像显示"></a>A. 图像显示</h3><p>下面的这个程序是通过接受命令行参数来实现显示的节点，利用这个程序可以显示每个话题下的图像。不过有一个小问题是我本来想做的是可以同一时间多个窗口显示多个图像，这样效果会好很多。但是由于我电脑性能的问题跑起来很卡，但是显示单独的话题倒是很不错</p>
<pre class="line-numbers language-python"><code class="language-python"><span class="token comment" spellcheck="true">#! /home/jack/anaconda3/envs/ros/bin/python</span>

<span class="token triple-quoted-string string">""" 命令行快捷查看iai-kinect2图像的节点 """</span>

<span class="token triple-quoted-string string">"""
@author: Jack Wang
@copyright: Jack Wang
@date: 2021-11-20
"""</span>

<span class="token keyword">from</span> os <span class="token keyword">import</span> read
<span class="token keyword">import</span> sys
<span class="token keyword">import</span> argparse
<span class="token keyword">from</span> typing <span class="token keyword">import</span> List

<span class="token keyword">import</span> cv2
<span class="token keyword">import</span> numpy <span class="token keyword">as</span> np


<span class="token keyword">for</span> path_idx <span class="token keyword">in</span> range<span class="token punctuation">(</span>len<span class="token punctuation">(</span>sys<span class="token punctuation">.</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">if</span> <span class="token string">"2.7"</span> <span class="token keyword">in</span> sys<span class="token punctuation">.</span>path<span class="token punctuation">[</span>path_idx<span class="token punctuation">]</span><span class="token punctuation">:</span>
        temp <span class="token operator">=</span> sys<span class="token punctuation">.</span>path<span class="token punctuation">.</span>pop<span class="token punctuation">(</span>path_idx<span class="token punctuation">)</span>
        <span class="token keyword">break</span>
sys<span class="token punctuation">.</span>path<span class="token punctuation">.</span>append<span class="token punctuation">(</span>temp<span class="token punctuation">)</span>

<span class="token keyword">import</span> rospy
<span class="token keyword">from</span> cv_bridge <span class="token keyword">import</span> CvBridge
<span class="token keyword">from</span> sensor_msgs<span class="token punctuation">.</span>msg <span class="token keyword">import</span> Image<span class="token punctuation">,</span> CompressedImage


<span class="token keyword">class</span> <span class="token class-name">iaiKinect2Viewer</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">:</span>
    bridge <span class="token operator">=</span> CvBridge<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> args<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> None<span class="token punctuation">:</span>
        super<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>__init__<span class="token punctuation">(</span><span class="token punctuation">)</span>
        self<span class="token punctuation">.</span>subcribers<span class="token punctuation">:</span> List<span class="token punctuation">[</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
        self<span class="token punctuation">.</span>windows_idx <span class="token operator">=</span> <span class="token number">0</span>
        <span class="token keyword">assert</span> len<span class="token punctuation">(</span>args<span class="token punctuation">.</span>topic<span class="token punctuation">)</span> <span class="token operator">%</span> len<span class="token punctuation">(</span>args<span class="token punctuation">.</span>quality<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">,</span> f<span class="token string">"话题数不匹配"</span>
        group_num <span class="token operator">=</span> len<span class="token punctuation">(</span>args<span class="token punctuation">.</span>topic<span class="token punctuation">)</span> <span class="token operator">//</span> len<span class="token punctuation">(</span>args<span class="token punctuation">.</span>quality<span class="token punctuation">)</span>
        <span class="token keyword">for</span> quality <span class="token keyword">in</span> args<span class="token punctuation">.</span>quality<span class="token punctuation">:</span>
            <span class="token keyword">for</span> i <span class="token keyword">in</span> range<span class="token punctuation">(</span>group_num<span class="token punctuation">)</span><span class="token punctuation">:</span>
                temp_topic <span class="token operator">=</span> args<span class="token punctuation">.</span>topic<span class="token punctuation">.</span>pop<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
                self<span class="token punctuation">.</span>add_subscriber<span class="token punctuation">(</span>quality<span class="token punctuation">,</span> temp_topic<span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">add_subscriber</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> quality<span class="token punctuation">:</span> str<span class="token punctuation">,</span> topic<span class="token punctuation">:</span> str<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token keyword">assert</span> quality <span class="token keyword">in</span> <span class="token punctuation">[</span><span class="token string">"sd"</span><span class="token punctuation">,</span> <span class="token string">"qhd"</span><span class="token punctuation">,</span><span class="token string">"hd"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> f<span class="token string">"无效的话题组"</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span>quality<span class="token punctuation">,</span> topic<span class="token punctuation">)</span>
        topic <span class="token operator">=</span> topic<span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">"_"</span><span class="token punctuation">)</span>
        prefix <span class="token operator">=</span> <span class="token string">"/kinect2"</span>
        <span class="token keyword">if</span> <span class="token string">"color"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_color_rect"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"color"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_color_rect"</span><span class="token punctuation">,</span><span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"color"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token operator">not</span> <span class="token keyword">in</span>  topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_color"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"color"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token operator">not</span> <span class="token keyword">in</span>  topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_color"</span><span class="token punctuation">,</span> <span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"depth"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_depth_rect"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"depth"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_depth_rect"</span><span class="token punctuation">,</span> <span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"mono"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_mono_rect"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"mono"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_mono_rect"</span><span class="token punctuation">,</span><span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"mono"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token operator">not</span> <span class="token keyword">in</span>  topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_mono"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"mono"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token operator">not</span> <span class="token keyword">in</span>  topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_mono"</span><span class="token punctuation">,</span> <span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"ir"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_ir_rect"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"ir"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_ir_rect"</span><span class="token punctuation">,</span><span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"ir"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token operator">not</span> <span class="token keyword">in</span>  topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token operator">not</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_ir"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>Image<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_images<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">elif</span> <span class="token string">"ir"</span> <span class="token keyword">in</span> topic <span class="token operator">and</span> <span class="token string">"rect"</span> <span class="token operator">not</span> <span class="token keyword">in</span>  topic <span class="token operator">and</span> <span class="token string">"compressed"</span> <span class="token keyword">in</span> topic<span class="token punctuation">:</span>
            self<span class="token punctuation">.</span>subcribers<span class="token punctuation">.</span>append<span class="token punctuation">(</span>rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"/"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token punctuation">[</span>prefix<span class="token punctuation">,</span> quality<span class="token punctuation">,</span> <span class="token string">"image_ir"</span><span class="token punctuation">,</span> <span class="token string">"compressed"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>show_compressed_image<span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> callback_args<span class="token operator">=</span>self<span class="token punctuation">.</span>windows_idx<span class="token punctuation">)</span><span class="token punctuation">)</span>
            self<span class="token punctuation">.</span>windows_idx <span class="token operator">+=</span> <span class="token number">1</span>
        <span class="token keyword">else</span><span class="token punctuation">:</span>
            <span class="token keyword">assert</span> <span class="token boolean">False</span><span class="token punctuation">,</span> f<span class="token string">"无效的参数：qualitt={quality}, topic={topic}"</span>

    <span class="token keyword">def</span> <span class="token function">show_images</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> img<span class="token punctuation">,</span> window_idx<span class="token punctuation">)</span><span class="token punctuation">:</span>
        cv_img <span class="token operator">=</span> self<span class="token punctuation">.</span>bridge<span class="token punctuation">.</span>imgmsg_to_cv2<span class="token punctuation">(</span>img_msg<span class="token operator">=</span>img<span class="token punctuation">)</span>
        cv2<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>f<span class="token string">"viewer_{window_idx}"</span><span class="token punctuation">,</span> cv_img<span class="token punctuation">)</span>
        <span class="token keyword">if</span> cv2<span class="token punctuation">.</span>waitKey<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">:</span>
            cv2<span class="token punctuation">.</span>destroyAllWindows<span class="token punctuation">(</span><span class="token punctuation">)</span>
            rospy<span class="token punctuation">.</span>signal_shutdown<span class="token punctuation">(</span>reason<span class="token operator">=</span><span class="token string">"pressed esc"</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">show_compressed_image</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> img<span class="token punctuation">:</span> CompressedImage<span class="token punctuation">,</span> windows_idx<span class="token punctuation">)</span><span class="token punctuation">:</span>
        cv_img <span class="token operator">=</span> self<span class="token punctuation">.</span>bridge<span class="token punctuation">.</span>compressed_imgmsg_to_cv2<span class="token punctuation">(</span>cmprs_img_msg<span class="token operator">=</span>img<span class="token punctuation">)</span>
        cv2<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span>f<span class="token string">"viewer_{windows_idx}"</span><span class="token punctuation">,</span> cv_img<span class="token punctuation">)</span>
        <span class="token keyword">if</span> cv2<span class="token punctuation">.</span>waitKey<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">:</span>
            cv2<span class="token punctuation">.</span>destroyAllWindows<span class="token punctuation">(</span><span class="token punctuation">)</span>
            rospy<span class="token punctuation">.</span>signal_shutdown<span class="token punctuation">(</span>reason<span class="token operator">=</span><span class="token string">"pressed esc"</span><span class="token punctuation">)</span>


<span class="token keyword">def</span> <span class="token function">arg_parser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> argparse<span class="token punctuation">.</span>Namespace<span class="token punctuation">:</span>
    parser <span class="token operator">=</span> argparse<span class="token punctuation">.</span>ArgumentParser<span class="token punctuation">(</span>description<span class="token operator">=</span><span class="token string">"本程序用于可视化显示iai-kinect2的不同话题中的图片，以对比他们的不同"</span><span class="token punctuation">)</span>
    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"-q"</span><span class="token punctuation">,</span> <span class="token string">"--quality"</span><span class="token punctuation">,</span> dest<span class="token operator">=</span><span class="token string">"quality"</span><span class="token punctuation">,</span> nargs<span class="token operator">=</span><span class="token string">"*"</span><span class="token punctuation">,</span> type<span class="token operator">=</span>str<span class="token punctuation">,</span> help<span class="token operator">=</span><span class="token string">"指定需要显示图像的话题组"</span><span class="token punctuation">)</span>
    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"-t"</span><span class="token punctuation">,</span> <span class="token string">"--topic"</span><span class="token punctuation">,</span> dest<span class="token operator">=</span><span class="token string">"topic"</span><span class="token punctuation">,</span> nargs<span class="token operator">=</span><span class="token string">"+"</span><span class="token punctuation">,</span> type<span class="token operator">=</span>str<span class="token punctuation">,</span> help<span class="token operator">=</span><span class="token string">"指定需要显示图像的话题"</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> parser<span class="token punctuation">.</span>parse_args<span class="token punctuation">(</span><span class="token punctuation">)</span>


<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    args <span class="token operator">=</span> arg_parser<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span>args<span class="token punctuation">.</span>quality<span class="token punctuation">,</span> args<span class="token punctuation">.</span>topic<span class="token punctuation">)</span>
    rospy<span class="token punctuation">.</span>init_node<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"ini_kinect2_viewer"</span><span class="token punctuation">)</span>
    viewer <span class="token operator">=</span> iaiKinect2Viewer<span class="token punctuation">(</span>args<span class="token operator">=</span>args<span class="token punctuation">)</span>
    rospy<span class="token punctuation">.</span>spin<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>使用的话则在命令行中加上参数，<code>-q</code>表示图像的质量，即<code>qhd</code>、<code>sd</code>还是<code>hd</code>，<code>-t</code>表示显示的话题。写的时候是支持多个话题同时显示的，但是不知道哪里出问题了显示不出来</p>
<pre class="line-numbers language-bash"><code class="language-bash"><span class="token comment" spellcheck="true"># 显示单个话题的图像：1/4 大小的灰度图</span>
<span class="token punctuation">(</span>ros<span class="token punctuation">)</span> jack@jack-Alienware-m15-R3:~/project/install_iai_kinect2$ rosrun look_kenect2 look_images.py -q qhd -t mono
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120152240529.png" alt="qhd中mono里的黑白图像"></p>
<pre class="line-numbers language-bash"><code class="language-bash"><span class="token comment" spellcheck="true"># 显示单个话题的图像：1/4 大小的彩色图</span>
<span class="token punctuation">(</span>ros<span class="token punctuation">)</span> jack@jack-Alienware-m15-R3:~/project/install_iai_kinect2$ rosrun look_kenect2 look_images.py -q qhd -t color
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120152424998.png" alt="qhd中color里的彩色图像"></p>
<pre class="line-numbers language-bash"><code class="language-bash"><span class="token comment" spellcheck="true"># 显示单个话题的图像：1/4 大小的深度图</span>
<span class="token punctuation">(</span>ros<span class="token punctuation">)</span> jack@jack-Alienware-m15-R3:~/project/install_iai_kinect2$ rosrun look_kenect2 look_images.py -q qhd -t depth_compressed
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>需要说明的是，qhd和hd中的深度图像如果不用compressed，即直接用的kinect采集到的的点的话，那么显示的非常卡，因为点云的数据实在是太大了，用而compressed中的数据则是iai-kinect2经过OpenCL、CUDA加速渲染之后得到的，因此帧率比较高。此外获取到的深度图每个像素都是一个以毫米为单位的距离值，因此使用OpenCV直接显示的话被做了归一化，所以越近的地方越黑，越远的地方越白，一些异常点，即没有反射的点距离被认为是摄像头获取距离的极限值（&gt;1200，即超过12米），因此这些异常点使得归一化之后基本都是黑的，我们自己使用的时候一定要先处理异常点然后再归一化，最后再显示</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120153143101.png" alt="qhd里的深度图"></p>
<pre class="line-numbers language-bash"><code class="language-bash"><span class="token comment" spellcheck="true"># 显示单个话题的图像：sd大小的红外图像</span>
<span class="token punctuation">(</span>ros<span class="token punctuation">)</span> jack@jack-Alienware-m15-R3:~/project/install_iai_kinect2$ rosrun look_kenect2 look_images.py -q sd -t ir_rect
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>需要说明的是，Kinect V2相机有一个红外发射器，一个红外接收器，因此距离越近，表面越光滑，接收器接收到反射的红外线越强，数值越高，对应就越白</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120154330718.png" alt="sd里的红外图"></p>
<pre class="line-numbers language-bash"><code class="language-bash"><span class="token comment" spellcheck="true"># 显示单个话题的图像：sd大小的色彩图</span>
^<span class="token punctuation">(</span>ros<span class="token punctuation">)</span> jack@jack-Alienware-m15-R3:~/project/install_iai_kinect2$ rosrun look_kenect2 look_images.py -q sd -t color_rect
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>理论上来说，sd话题里显示的都是红外相机拍摄得到的图片，因此不会存在颜色，所以这里其实是把RGB相机拍到的图片和红外相机图片配准之后的结果</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211120154705830.png" alt="sd里的color_rect"></p>
<h3 id="B-YOLO-V5进行物体检测"><a href="#B-YOLO-V5进行物体检测" class="headerlink" title="B. YOLO V5进行物体检测"></a>B. YOLO V5进行物体检测</h3><p>利用之前写好的YOLO V5，可以实现物体检测，然后根据深度图像来标注出物体的距离</p>
<p>YOLO V5的代码后面整理出来会放出来，这里先用一用，下面的代码需要注意的是rospy中的message_filter如果消息频率速度过快，甚至快过了message_filter处理的速度，那么就会导致两个消息无法对应起来，因此就永远不会调用回调函数，因此cv2.waitkey需要等10毫秒左右</p>
<pre class="line-numbers language-python"><code class="language-python"><span class="token comment" spellcheck="true">#! /home/jack/anaconda3/envs/ros/bin/python</span>

<span class="token keyword">import</span> sys
<span class="token keyword">import</span> time
<span class="token keyword">from</span> pathlib <span class="token keyword">import</span> Path

<span class="token keyword">import</span> cv2
<span class="token keyword">import</span> numpy <span class="token keyword">as</span> np
<span class="token keyword">from</span> colorama <span class="token keyword">import</span> Fore<span class="token punctuation">,</span> Style

<span class="token keyword">from</span> libyolo <span class="token keyword">import</span> YoloV5s

temp_path <span class="token operator">=</span> None
<span class="token keyword">for</span> path_idx <span class="token keyword">in</span> range<span class="token punctuation">(</span>len<span class="token punctuation">(</span>sys<span class="token punctuation">.</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">if</span> <span class="token string">"2.7"</span> <span class="token keyword">in</span> sys<span class="token punctuation">.</span>path<span class="token punctuation">[</span>path_idx<span class="token punctuation">]</span><span class="token punctuation">:</span>
        temp_path <span class="token operator">=</span> sys<span class="token punctuation">.</span>path<span class="token punctuation">.</span>pop<span class="token punctuation">(</span>path_idx<span class="token punctuation">)</span>
        <span class="token keyword">break</span>
<span class="token keyword">if</span> temp_path <span class="token keyword">is</span> <span class="token operator">not</span> None<span class="token punctuation">:</span>
    sys<span class="token punctuation">.</span>path<span class="token punctuation">.</span>append<span class="token punctuation">(</span>temp_path<span class="token punctuation">)</span>

<span class="token keyword">import</span> rospy
<span class="token keyword">import</span> message_filters
<span class="token keyword">from</span> sensor_msgs<span class="token punctuation">.</span>msg <span class="token keyword">import</span> CompressedImage
<span class="token keyword">from</span> cv_bridge <span class="token keyword">import</span> CvBridge


<span class="token keyword">class</span> <span class="token class-name">DetectYoloKinect</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">:</span>
    yolo <span class="token operator">=</span> YoloV5s<span class="token punctuation">(</span>weight_path<span class="token operator">=</span>Path<span class="token punctuation">(</span>__file__<span class="token punctuation">)</span><span class="token punctuation">.</span>resolve<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>parent<span class="token punctuation">.</span>parent<span class="token punctuation">.</span>joinpath<span class="token punctuation">(</span><span class="token string">"models"</span><span class="token punctuation">,</span> <span class="token string">"yolov5s.pt"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    bridge <span class="token operator">=</span> CvBridge<span class="token punctuation">(</span><span class="token punctuation">)</span>
    font <span class="token operator">=</span> cv2<span class="token punctuation">.</span>FONT_HERSHEY_DUPLEX

    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> rgb_img_topic<span class="token punctuation">:</span> str<span class="token punctuation">,</span> depth_img_topic<span class="token punctuation">:</span> str<span class="token punctuation">,</span> if_detection_only<span class="token punctuation">:</span> bool <span class="token operator">=</span> <span class="token boolean">False</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> None<span class="token punctuation">:</span>
        super<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>__init__<span class="token punctuation">(</span><span class="token punctuation">)</span>
        rospy<span class="token punctuation">.</span>loginfo<span class="token punctuation">(</span>msg<span class="token operator">=</span>f<span class="token string">"{Fore.GREEN}启动物体检测节点！{Style.RESET_ALL}"</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> if_detection_only<span class="token punctuation">:</span>
            rospy<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>name<span class="token operator">=</span>rgb_img_topic<span class="token punctuation">,</span> data_class<span class="token operator">=</span>CompressedImage<span class="token punctuation">,</span> callback<span class="token operator">=</span>self<span class="token punctuation">.</span>_detect_only_cb<span class="token punctuation">,</span>
                             queue_size<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">)</span>
        <span class="token keyword">else</span><span class="token punctuation">:</span>
            rgb_subscriber <span class="token operator">=</span> message_filters<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>rgb_img_topic<span class="token punctuation">,</span> CompressedImage<span class="token punctuation">)</span>
            depth_subscriber <span class="token operator">=</span> message_filters<span class="token punctuation">.</span>Subscriber<span class="token punctuation">(</span>depth_img_topic<span class="token punctuation">,</span> CompressedImage<span class="token punctuation">)</span>
            sync <span class="token operator">=</span> message_filters<span class="token punctuation">.</span>ApproximateTimeSynchronizer<span class="token punctuation">(</span>fs<span class="token operator">=</span><span class="token punctuation">[</span>rgb_subscriber<span class="token punctuation">,</span> depth_subscriber<span class="token punctuation">]</span><span class="token punctuation">,</span> queue_size<span class="token operator">=</span><span class="token number">100</span><span class="token punctuation">,</span>
                                                               slop<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span>
            sync<span class="token punctuation">.</span>registerCallback<span class="token punctuation">(</span>self<span class="token punctuation">.</span>_multi_cb<span class="token punctuation">)</span>
        self<span class="token punctuation">.</span>last_time_rgb <span class="token operator">=</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">_detect_only_cb</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> img<span class="token punctuation">:</span> CompressedImage<span class="token punctuation">)</span><span class="token punctuation">:</span>
        cv_image<span class="token punctuation">:</span> np<span class="token punctuation">.</span>ndarray <span class="token operator">=</span> self<span class="token punctuation">.</span>bridge<span class="token punctuation">.</span>compressed_imgmsg_to_cv2<span class="token punctuation">(</span>cmprs_img_msg<span class="token operator">=</span>img<span class="token punctuation">)</span>
        result_dict<span class="token punctuation">,</span> draw_img <span class="token operator">=</span> self<span class="token punctuation">.</span>yolo<span class="token punctuation">.</span>inference<span class="token punctuation">(</span>cv_image<span class="token punctuation">,</span> if_absolute<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> if_show<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
        t2 <span class="token operator">=</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span>
        draw_img <span class="token operator">=</span> cv2<span class="token punctuation">.</span>putText<span class="token punctuation">(</span>draw_img<span class="token punctuation">,</span> f<span class="token string">"fps: {1 / (t2 - self.last_time_rgb):>5.2f}, seq_id: {img.header.seq}"</span><span class="token punctuation">,</span>
                               <span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">,</span> self<span class="token punctuation">.</span>font<span class="token punctuation">,</span> <span class="token number">0.8</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span>
        self<span class="token punctuation">.</span>last_time_rgb <span class="token operator">=</span> t2
        cv2<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span><span class="token string">"color_detections"</span><span class="token punctuation">,</span> draw_img<span class="token punctuation">)</span>
        <span class="token keyword">if</span> cv2<span class="token punctuation">.</span>waitKey<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">:</span>
            cv2<span class="token punctuation">.</span>destroyAllWindows<span class="token punctuation">(</span><span class="token punctuation">)</span>
            rospy<span class="token punctuation">.</span>logwarn<span class="token punctuation">(</span><span class="token string">"按下了ESC键，终止节点..."</span><span class="token punctuation">)</span>
            rospy<span class="token punctuation">.</span>signal_shutdown<span class="token punctuation">(</span>reason<span class="token operator">=</span><span class="token string">"pressed esc"</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">_multi_cb</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> rgb_img<span class="token punctuation">:</span> CompressedImage<span class="token punctuation">,</span> depth_img<span class="token punctuation">:</span> CompressedImage<span class="token punctuation">)</span><span class="token punctuation">:</span>
        rospy<span class="token punctuation">.</span>loginfo<span class="token punctuation">(</span><span class="token string">"Getting into _multi_cb"</span><span class="token punctuation">)</span>
        cv_rgb<span class="token punctuation">:</span> np<span class="token punctuation">.</span>ndarray <span class="token operator">=</span> self<span class="token punctuation">.</span>bridge<span class="token punctuation">.</span>compressed_imgmsg_to_cv2<span class="token punctuation">(</span>cmprs_img_msg<span class="token operator">=</span>rgb_img<span class="token punctuation">)</span>
        cv_depth<span class="token punctuation">:</span> np<span class="token punctuation">.</span>ndarray <span class="token operator">=</span> self<span class="token punctuation">.</span>bridge<span class="token punctuation">.</span>compressed_imgmsg_to_cv2<span class="token punctuation">(</span>cmprs_img_msg<span class="token operator">=</span>depth_img<span class="token punctuation">)</span>
        cv_depth_draw<span class="token punctuation">:</span> np<span class="token punctuation">.</span>ndarray <span class="token operator">=</span> np<span class="token punctuation">.</span>stack<span class="token punctuation">(</span><span class="token punctuation">[</span>cv_depth<span class="token punctuation">]</span> <span class="token operator">*</span> <span class="token number">3</span><span class="token punctuation">,</span> axis<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># to BGR</span>
        cv_depth_draw <span class="token operator">=</span> <span class="token punctuation">(</span>cv_depth_draw <span class="token operator">-</span> cv_depth_draw<span class="token punctuation">.</span>min<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">(</span>cv_depth_draw<span class="token punctuation">.</span>max<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cv_depth_draw<span class="token punctuation">.</span>min<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true"># inference</span>
        result_dict<span class="token punctuation">,</span> cv_rgb_draw <span class="token operator">=</span> self<span class="token punctuation">.</span>yolo<span class="token punctuation">.</span>inference<span class="token punctuation">(</span>cv_rgb<span class="token punctuation">,</span> if_absolute<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> if_show<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true"># log time</span>
        t <span class="token operator">=</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span>
        fps <span class="token operator">=</span> round<span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token punctuation">(</span>t <span class="token operator">-</span> self<span class="token punctuation">.</span>last_time_rgb<span class="token punctuation">)</span><span class="token punctuation">,</span> ndigits<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>
        self<span class="token punctuation">.</span>last_time_rgb <span class="token operator">=</span> t

        rospy<span class="token punctuation">.</span>loginfo<span class="token punctuation">(</span>msg<span class="token operator">=</span><span class="token string">"Done inference, start to draw"</span><span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true"># draw basic info</span>
        cv_rgb_draw <span class="token operator">=</span> cv2<span class="token punctuation">.</span>putText<span class="token punctuation">(</span>cv_rgb_draw<span class="token punctuation">,</span> f<span class="token string">"FPS:{fps}, seq:{depth_img.header.seq}"</span><span class="token punctuation">,</span>
                                  org<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">,</span> fontFace<span class="token operator">=</span>self<span class="token punctuation">.</span>font<span class="token punctuation">,</span> fontScale<span class="token operator">=</span><span class="token number">0.8</span><span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> thickness<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>
        cv_depth_draw <span class="token operator">=</span> cv2<span class="token punctuation">.</span>putText<span class="token punctuation">(</span>cv_depth_draw<span class="token punctuation">,</span> f<span class="token string">"FPS:{fps}, seq:{depth_img.header.seq}"</span><span class="token punctuation">,</span>
                                    org<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">,</span> fontFace<span class="token operator">=</span>self<span class="token punctuation">.</span>font<span class="token punctuation">,</span> fontScale<span class="token operator">=</span><span class="token number">0.8</span><span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> thickness<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>

        <span class="token comment" spellcheck="true"># draw depth</span>
        rospy<span class="token punctuation">.</span>loginfo<span class="token punctuation">(</span>msg<span class="token operator">=</span><span class="token string">"Done draw basic, start draw depth"</span><span class="token punctuation">)</span>
        <span class="token keyword">for</span> d_type<span class="token punctuation">,</span> items <span class="token keyword">in</span> result_dict<span class="token punctuation">.</span>items<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
            <span class="token keyword">for</span> item <span class="token keyword">in</span> items<span class="token punctuation">:</span>
                <span class="token comment" spellcheck="true"># 周围100个点的平均，yolo的结果已经确保点在图像内</span>
                depth <span class="token operator">=</span> self<span class="token punctuation">.</span>__get_depth<span class="token punctuation">(</span><span class="token punctuation">(</span>x <span class="token punctuation">:</span><span class="token operator">=</span> item<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>y <span class="token punctuation">:</span><span class="token operator">=</span> item<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> depth_image<span class="token operator">=</span>cv_depth<span class="token punctuation">,</span> area_size<span class="token operator">=</span><span class="token number">20</span><span class="token punctuation">)</span>
                x<span class="token punctuation">,</span> y <span class="token operator">=</span> int<span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">,</span> int<span class="token punctuation">(</span>y<span class="token punctuation">)</span>
                cv_depth_draw <span class="token operator">=</span> cv2<span class="token punctuation">.</span>putText<span class="token punctuation">(</span>cv_depth_draw<span class="token punctuation">,</span> text<span class="token operator">=</span>f<span class="token string">"{d_type}, {depth / 10:>.2f}m"</span><span class="token punctuation">,</span> org<span class="token operator">=</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token number">-5</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                            fontFace<span class="token operator">=</span>self<span class="token punctuation">.</span>font<span class="token punctuation">,</span> fontScale<span class="token operator">=</span><span class="token number">0.8</span><span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> lineType<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>
                cv_depth_draw <span class="token operator">=</span> cv2<span class="token punctuation">.</span>circle<span class="token punctuation">(</span>cv_depth_draw<span class="token punctuation">,</span> center<span class="token operator">=</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">,</span> radius<span class="token operator">=</span><span class="token number">5</span><span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                                           thickness<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> lineType<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>
        rospy<span class="token punctuation">.</span>loginfo<span class="token punctuation">(</span>msg<span class="token operator">=</span>f<span class="token string">"Done Drawing"</span><span class="token punctuation">)</span>
        cv2<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span><span class="token string">"detection_result"</span><span class="token punctuation">,</span> cv_rgb_draw<span class="token punctuation">)</span>
        cv2<span class="token punctuation">.</span>imshow<span class="token punctuation">(</span><span class="token string">"depth_result"</span><span class="token punctuation">,</span> cv_depth_draw<span class="token punctuation">)</span>
        <span class="token keyword">if</span> cv2<span class="token punctuation">.</span>waitKey<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">:</span>
            cv2<span class="token punctuation">.</span>destroyAllWindows<span class="token punctuation">(</span><span class="token punctuation">)</span>
            rospy<span class="token punctuation">.</span>logwarn<span class="token punctuation">(</span>msg<span class="token operator">=</span>f<span class="token string">"按下了ESC键，手动关闭了节点"</span><span class="token punctuation">)</span>
            rospy<span class="token punctuation">.</span>signal_shutdown<span class="token punctuation">(</span>reason<span class="token operator">=</span><span class="token string">"pressed esc"</span><span class="token punctuation">)</span>

    @staticmethod
    <span class="token keyword">def</span> <span class="token function">__get_depth</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> float<span class="token punctuation">,</span> y<span class="token punctuation">:</span> float<span class="token punctuation">,</span> depth_image<span class="token punctuation">:</span> np<span class="token punctuation">.</span>ndarray<span class="token punctuation">,</span> area_size<span class="token punctuation">:</span> int <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> float<span class="token punctuation">:</span>
        boundary <span class="token operator">=</span> <span class="token punctuation">[</span>int<span class="token punctuation">(</span>position<span class="token punctuation">)</span> <span class="token keyword">for</span> position <span class="token keyword">in</span>
                    <span class="token punctuation">[</span>y <span class="token operator">-</span> area_size <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">,</span> y <span class="token operator">+</span> area_size <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">,</span> x <span class="token operator">-</span> area_size <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">,</span> x <span class="token operator">+</span> area_size <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
        <span class="token keyword">return</span> depth_image<span class="token punctuation">[</span>boundary<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">:</span>boundary<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> boundary<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">:</span>boundary<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">.</span>mean<span class="token punctuation">(</span><span class="token punctuation">)</span>


<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    rospy<span class="token punctuation">.</span>init_node<span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"detect_yolo_kinect2"</span><span class="token punctuation">,</span> anonymous<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span>
    dyk <span class="token operator">=</span> DetectYoloKinect<span class="token punctuation">(</span>rgb_img_topic<span class="token operator">=</span><span class="token string">"/kinect2/qhd/image_color/compressed"</span><span class="token punctuation">,</span>
                           depth_img_topic<span class="token operator">=</span><span class="token string">"/kinect2/qhd/image_depth_rect/compressed"</span><span class="token punctuation">,</span> if_detection_only<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span>
    rospy<span class="token punctuation">.</span>spin<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>最后得到的效果如下，可以看到YOLO还是可以的，不过有的时候会识别错误，例如把纸板识别成了沙发。而且在深度图中，越靠近边缘实际上越不准确，如果没有反射回来的话距离就被记为0。</p>
<p><img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211121155602208.png" alt="YOLO和深度图配准"></p>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/about" rel="external nofollow noreferrer">Jack Wang</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://jackwang0107.github.io/2021/11/19/ros-za-pian-ros-zhong-shi-yong-kinect-v2-iai-kinect-shi-yong/">https://jackwang0107.github.io/2021/11/19/ros-za-pian-ros-zhong-shi-yong-kinect-v2-iai-kinect-shi-yong/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/about" target="_blank">Jack Wang</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/tags/Ubuntu/">
                                    <span class="chip bg-color">Ubuntu</span>
                                </a>
                            
                                <a href="/tags/ROS/">
                                    <span class="chip bg-color">ROS</span>
                                </a>
                            
                                <a href="/tags/roslaunch/">
                                    <span class="chip bg-color">roslaunch</span>
                                </a>
                            
                                <a href="/tags/cv-bridge/">
                                    <span class="chip bg-color">cv_bridge</span>
                                </a>
                            
                                <a href="/tags/melodic/">
                                    <span class="chip bg-color">melodic</span>
                                </a>
                            
                                <a href="/tags/OpenCv/">
                                    <span class="chip bg-color">OpenCv</span>
                                </a>
                            
                                <a href="/tags/sensor-msgs/">
                                    <span class="chip bg-color">sensor_msgs</span>
                                </a>
                            
                                <a href="/tags/Kinect-V2/">
                                    <span class="chip bg-color">Kinect V2</span>
                                </a>
                            
                                <a href="/tags/iai-kinect2/">
                                    <span class="chip bg-color">iai-kinect2</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/medias/reward/alipay.png" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/medias/reward/wechat.jpg" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/2021/11/23/ros-za-pian-melodic-xia-python3-zhong-shi-yong-cv-bridge-yu-tf/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/9.jpg" class="responsive-img" alt="ROS杂篇 Melodic下Python3中使用CV_Bridge与TF">
                        
                        <span class="card-title">ROS杂篇 Melodic下Python3中使用CV_Bridge与TF</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            Melodic版本中Python3下使用这两个包却会报错，本文将解决这Python3CV_Bridge与TF的使用问题。
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-11-23
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/ROS%E6%9D%82%E7%AF%87/" class="post-category">
                                    ROS杂篇
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/Ubuntu/">
                        <span class="chip bg-color">Ubuntu</span>
                    </a>
                    
                    <a href="/tags/ROS/">
                        <span class="chip bg-color">ROS</span>
                    </a>
                    
                    <a href="/tags/roslaunch/">
                        <span class="chip bg-color">roslaunch</span>
                    </a>
                    
                    <a href="/tags/cv-bridge/">
                        <span class="chip bg-color">cv_bridge</span>
                    </a>
                    
                    <a href="/tags/melodic/">
                        <span class="chip bg-color">melodic</span>
                    </a>
                    
                    <a href="/tags/OpenCv/">
                        <span class="chip bg-color">OpenCv</span>
                    </a>
                    
                    <a href="/tags/tf2/">
                        <span class="chip bg-color">tf2</span>
                    </a>
                    
                    <a href="/tags/sensor-msgs/">
                        <span class="chip bg-color">sensor_msgs</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/2021/11/18/ros-za-pian-an-zhuang-kinect-v2-qu-dong/">
                    <div class="card-image">
                        
                        <img src="https://jack-1307599355.cos.ap-shanghai.myqcloud.com/img/image-20211118214830894.png" class="responsive-img" alt="ROS杂篇 ROS中使用Kinect V2 Part1：安装+使用">
                        
                        <span class="card-title">ROS杂篇 ROS中使用Kinect V2 Part1：安装+使用</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            Kinect是非常流行的获取深度、彩色、点云的相机。本文介绍了Kinect相机的具体性能，以及如何在ROS调用Kinect相机。
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-11-18
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/ROS%E6%9D%82%E7%AF%87/" class="post-category">
                                    ROS杂篇
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/Ubuntu/">
                        <span class="chip bg-color">Ubuntu</span>
                    </a>
                    
                    <a href="/tags/ROS/">
                        <span class="chip bg-color">ROS</span>
                    </a>
                    
                    <a href="/tags/melodic/">
                        <span class="chip bg-color">melodic</span>
                    </a>
                    
                    <a href="/tags/Kinect-V2/">
                        <span class="chip bg-color">Kinect V2</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>


<script>
    $('#articleContent').on('copy', function (e) {
        // IE8 or earlier browser is 'undefined'
        if (typeof window.getSelection === 'undefined') return;

        var selection = window.getSelection();
        // if the selection is short let's not annoy our users.
        if (('' + selection).length < Number.parseInt('120')) {
            return;
        }

        // create a div outside of the visible area and fill it with the selected text.
        var bodyElement = document.getElementsByTagName('body')[0];
        var newdiv = document.createElement('div');
        newdiv.style.position = 'absolute';
        newdiv.style.left = '-99999px';
        bodyElement.appendChild(newdiv);
        newdiv.appendChild(selection.getRangeAt(0).cloneContents());

        // we need a <pre> tag workaround.
        // otherwise the text inside "pre" loses all the line breaks!
        if (selection.getRangeAt(0).commonAncestorContainer.nodeName === 'PRE' || selection.getRangeAt(0).commonAncestorContainer.nodeName === 'CODE') {
            newdiv.innerHTML = "<pre>" + newdiv.innerHTML + "</pre>";
        }

        var url = document.location.href;
        newdiv.innerHTML += '<br />'
            + '来源: JackWang&#39;s Blog<br />'
            + '文章作者: Jack Wang<br />'
            + '文章链接: <a href="' + url + '">' + url + '</a><br />'
            + '本文章著作权归作者所有，任何形式的转载都请注明出处。';

        selection.selectAllChildren(newdiv);
        window.setTimeout(function () {bodyElement.removeChild(newdiv);}, 200);
    });
</script>


<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('2'),
            headingSelector: 'h1, h2, h3, h4, h5, h6'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h1, h2, h3, h4, h5, h6').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    

    <div class="container row center-align"
         style="margin-bottom: 15px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2021-2023</span>
            
            <a href="/about" target="_blank">Jack Wang</a>
            <!-- |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a> -->
            <!-- |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a> -->
            <br>
            
                &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                        class="white-color">603.8k</span>
            
            
            
                
            
            
                <span id="busuanzi_container_site_pv">
                &nbsp;|&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;
                    <span id="busuanzi_value_site_pv" class="white-color"></span>
            </span>
            
            
                <span id="busuanzi_container_site_uv">
                &nbsp;|&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;
                    <span id="busuanzi_value_site_uv" class="white-color"></span>
            </span>
            
            <br>

            <!-- 运行天数提醒. -->
            
                <span id="sitetime"> Loading ...</span>
                <script>
                    var calcSiteTime = function () {
                        var seconds = 1000;
                        var minutes = seconds * 60;
                        var hours = minutes * 60;
                        var days = hours * 24;
                        var years = days * 365;
                        var today = new Date();
                        var startYear = "2021";
                        var startMonth = "11";
                        var startDate = "12";
                        var startHour = "0";
                        var startMinute = "0";
                        var startSecond = "0";
                        var todayYear = today.getFullYear();
                        var todayMonth = today.getMonth() + 1;
                        var todayDate = today.getDate();
                        var todayHour = today.getHours();
                        var todayMinute = today.getMinutes();
                        var todaySecond = today.getSeconds();
                        var t1 = Date.UTC(startYear, startMonth, startDate, startHour, startMinute, startSecond);
                        var t2 = Date.UTC(todayYear, todayMonth, todayDate, todayHour, todayMinute, todaySecond);
                        var diff = t2 - t1;
                        var diffYears = Math.floor(diff / years);
                        var diffDays = Math.floor((diff / days) - diffYears * 365);

                        // 区分是否有年份.
                        var language = 'zh-CN';
                        if (startYear === String(todayYear)) {
                            document.getElementById("year").innerHTML = todayYear;
                            var daysTip = 'This site has been running for ' + diffDays + ' days';
                            if (language === 'zh-CN') {
                                daysTip = '本站已运行 ' + diffDays + ' 天';
                            } else if (language === 'zh-HK') {
                                daysTip = '本站已運行 ' + diffDays + ' 天';
                            }
                            document.getElementById("sitetime").innerHTML = daysTip;
                        } else {
                            document.getElementById("year").innerHTML = startYear + " - " + todayYear;
                            var yearsAndDaysTip = 'This site has been running for ' + diffYears + ' years and '
                                + diffDays + ' days';
                            if (language === 'zh-CN') {
                                yearsAndDaysTip = '本站已运行 ' + diffYears + ' 年 ' + diffDays + ' 天';
                            } else if (language === 'zh-HK') {
                                yearsAndDaysTip = '本站已運行 ' + diffYears + ' 年 ' + diffDays + ' 天';
                            }
                            document.getElementById("sitetime").innerHTML = yearsAndDaysTip;
                        }
                    }

                    calcSiteTime();
                </script>
            
            <br>
            
                <span id="icp"><img src="/medias/icp.png"
                                    style="vertical-align: text-bottom;"/>
                <a href="https://beian.miit.gov.cn" target="_blank">陕ICP备2021014294号-1</a>
            </span>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/jackwang0108" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:2232123545@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=2232123545" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 2232123545" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/libs/materialize/materialize.min.js"></script>
    <script src="/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/libs/aos/aos.js"></script>
    <script src="/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/js/matery.js"></script>

    

    
        
        <script type="text/javascript">
            // 只在桌面版网页启用特效
            var windowWidth = $(window).width();
            if (windowWidth > 768) {
                document.write('<script type="text/javascript" src="/libs/others/sakura.js"><\/script>');
            }
        </script>
    

    <!-- 雪花特效 -->
    

    <!-- 鼠标星星特效 -->
    

     
        <script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>
        <script src="/libs/others/TencentCaptcha.js"></script>
        <button id="TencentCaptcha" data-appid="xxxxxxxxxx" data-cbfn="callback" type="button" hidden></button>
    

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    

    

    

    
    <script src="/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
